Interpreter: fix package blocks, eval STRING context, and compound assignment#231
Merged
Interpreter: fix package blocks, eval STRING context, and compound assignment#231
Conversation
…s are present
When JPERL_EVAL_USE_INTERPRETER=1, eval STRING was returning undef instead
of the last expression's value in two cases:
1. eval '1; END { }' returned undef because OperatorNode("undef") placeholder
for the END block overwrote lastResultReg after the real last expression.
2. INIT { eval 'END { }; 1' or die } returned undef because the eval body
was compiled in VOID context, discarding the result register entirely.
Fixes:
- CompileOperator: OperatorNode("undef") with no operand in VOID context
is a no-op, not LOAD_UNDEF (END/BEGIN/INIT/CHECK/UNITCHECK placeholders)
- BytecodeCompiler.visit(BlockNode): pre-scan to find last non-placeholder
statement; freeze lastResultReg after visiting it so trailing placeholders
cannot clobber it
- BytecodeCompiler.compile(): eval STRING body uses at least SCALAR context
so the result register is always allocated (never VOID)
… scope snapshot
When JPERL_EVAL_USE_INTERPRETER=1, bare names inside eval STRING (e.g.
*named{CODE}) were resolving to main:: instead of the correct package
at the eval call site (e.g. FOO3::named inside package FOO3 { }).
Root cause: BytecodeCompiler.symbolTable defaulted to 'main' and was
not being updated with the compile-time package/pragma state.
Fix mirrors the JVM compiler's approach exactly:
- CompileOperator: at EVAL_STRING emit time, snapshot the scope manager
(BytecodeCompiler.symbolTable.snapShot()) and store it as an
EmitterContext in RuntimeCode.evalContext under a unique evalTag,
exactly as EmitEval/evalTag does for JVM-compiled eval STRING.
The evalTag is baked into the EVAL_STRING opcode (4th field).
- SlowOpcodeHandler: read evalTag from opcode, pass to EvalStringHandler.
- EvalStringHandler: retrieve saved EmitterContext from evalContext,
use its symbolTable snapshot directly as the compile-time scope.
- BytecodeCompiler.compile(): sync package+pragmas from ctx.symbolTable
so BytecodeCompiler resolves bare names in the eval body correctly.
- RuntimeCode.evalStringWithInterpreter: use capturedSymbolTable
(compile-time scope from EmitEval) instead of RuntimeCode.getCurrentPackage()
which uses caller() and cannot see scoped package blocks.
Results: op/stash.t, comp/package_block.t, comp/parser.t now all show
identical pass counts between JVM and interpreter modes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes interpreter-mode regressions.\n\n## Changes\n\n- BytecodeCompiler: Honor per-argument context annotations in ListNode; thread eval STRING context; fix PUSH_PACKAGE/POP_PACKAGE scoped package blocks\n- BytecodeInterpreter: Handle PUSH_PACKAGE/POP_PACKAGE opcodes\n- EvalStringHandler: Use runtime package and propagate caller context\n- SlowOpcodeHandler: Pass callContext to evalString\n- CompileOperator: Emit callContext with EVAL_STRING opcode\n- CompileAssignment: Add lvalue context check matching JVM behavior\n- InterpretedCode: Package scope support\n- StatementParser: Package block parsing fix\n- RuntimeCode: Dynamic variable management improvements\n\n## Tests improved\n- comp/package_block.t: 0/5 → 4/5\n- comp/parser.t: improvements\n- op/postfixderef.t: improvements